#include "sniff.h"

int terminate = 0;

int get_iface_index(int fd, const char* interface_name)
{
	struct ifreq ifr;
    memset(&ifr, 0, sizeof(ifr));
    strcpy (ifr.ifr_name, interface_name);
    if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1) {
        return -1;
    }
    return ifr.ifr_ifindex;
}

int set_iface_promisc(int fd, int dev_id)
{
	struct packet_mreq mr;
	memset(&mr,0,sizeof(mr));
	mr.mr_ifindex = dev_id;
	mr.mr_type = PACKET_MR_PROMISC;

	if(setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,&mr,sizeof(mr))==-1)
	{
	   perror("setsockopt[PACKET_MR_PROMISC]");
	   return -1;
	}
	return 0;
}

int sniff_show(char *buf, uint32_t len)
{
	struct sockaddr_ll dest_sll;
	struct ether_header *eth_hdr;
	struct iphdr *ip;
	struct udphdr *udp;
	struct dhcp_packet *data;
	struct ip_udp_dhcp_packet packet;
	char *tmp;
	struct in_addr src, dest;
	uint16_t sport, dport;

	eth_hdr = (struct ether_header *)buf;

	ip = (struct iphdr *)(buf + sizeof(struct ether_header));
	
	if (ip->protocol != IPPROTO_UDP) // UDP demanded
		return -1;
	
	src.s_addr = ip->saddr;
	dest.s_addr = ip->daddr;
	
	udp = (struct udphdr *)(buf + sizeof(struct ether_header) + sizeof(struct iphdr)); 
	sport = ntohs(udp->source);
	dport = ntohs(udp->dest);
#define ISPORT(p) (dport == (p) || sport == (p))
	if (ISPORT(IPPORT_BOOTPC) || ISPORT(IPPORT_BOOTPS)) {	// BOOTP demanded
		int i;
		printf("----dump dhcp[[%s]--->>>>[%s]] frame----\n", 
			inet_ntoa(src), 
			inet_ntoa(dest));
		for(i=0;i<len;i++){
			printf("%02x ", buf[i] & 0xff);
		}
		printf("\n----------------------------------------------------\n");
	}
}

int sniff_recieve(int sock)
{
#define _MAX_FRAME_LEN_		8192

	uint8_t buf[_MAX_FRAME_LEN_] = {0};
	uint32_t frmlen = 0;

	frmlen = recv(sock, buf, _MAX_FRAME_LEN_, MSG_TRUNC);
	if (frmlen < 0){
		perror("Sniff - recv");
		return;
	}
	sniff_show(buf, frmlen);
	return 0;
}

int main(void)
{
	int sock, ifindex, res;
	struct sockaddr_ll ll;
	fd_set  fdset;

	sock = socket (PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
	if (sock < 0) {
		perror("Could not open raw socket\n");
		return -1;
	}

	if ((ifindex = get_iface_index(sock, "eth0")) < 0)
		return -1;

	memset(&ll, 0, sizeof(ll));
	ll.sll_family = PF_PACKET;
	ll.sll_ifindex = ifindex;
	ll.sll_protocol = htons(ETH_P_IP);

	if (bind(sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
		perror("bind[PF_PACKET]");
		goto err;
	}

	if(set_iface_promisc(sock, ifindex) == -1) {
		goto err;
	}

	while(!terminate) {
		FD_ZERO(&fdset);
		FD_SET(sock, &fdset);
		
		res = select(sock + 1, &fdset, NULL, NULL, NULL);
		if (res <= 0)
			continue;
		if (FD_ISSET(sock, &fdset)) {
			sniff_recieve(sock);
		}
	}

err:
	close(sock);
	return 0;
}

